Trapping Errors
This topic describes how to trap errors and handle exception events.
Trapping Errors
The example programs in this guide show specific VISA functionality and do not include error trapping. Error trapping, however, is good programming practice and is recommended in all your VISA application programs. To trap VISA errors you must check for VI_SUCCESS after each VISA function call.
If you want to ignore WARNINGS, you can test to see if err is less than (<) VI_SUCCESS. Since WARNINGS are greater than VI_SUCCESS and ERRORS are less than VI_SUCCESS, err_handler would only be called when the function returns an ERROR. For example:
if(err < VI_SUCCESS) err_handler (vi, err);
Example: Checking for VI_SUCCESS
This example illustrates checking for VI_SUCCESS. If VI_SUCCESS is not returned, an error handler (written by the programmer) is called. This must be done with each VISA function call.
ViStatus err;
.
.
err=viPrintf(vi, "*RST\n");
if (err < VI_SUCCESS) err_handler(vi, err);
.
Example: Printing Error Code
The following error handler prints a user-readable string describing the error code passed to the function:
void err_handler(ViSession vi, ViStatus err){
char err_msg[1024]={0};
viStatusDesc (vi, err, err_msg);
printf ("ERROR = %s\n", err_msg);
return;
}
Example: Checking Instrument Errors
When programming instruments, it is good practice to check the instrument to ensure there are no instrument errors after each instrument function. This example uses a SCPI command to check a specific instrument for errors.
void system_err(){
ViStatus err;
char buf[1024]={0};
int err_no;
err=viPrintf(vi, "SYSTEM:ERR?\n");
if (err < VI_SUCCESS) err_handler (vi, err);
err=viScanf (vi, "%d%t", &err_no, &buf);
if (err < VI_SUCCESS) err_handler (vi, err);
while (err_no >0){
printf ("Error Found: %d,%s\n", err_no, buf);
err=viScanf (vi, "%d%t", &err_no, &buf);
}
err=viFlush(vi, VI_READ_BUF);
if (err < VI_SUCCESS) err_handler (vi, err);
err=viFlush(vi, VI_WRITE_BUF);
if (err < VI_SUCCESS) err_handler (vi, err);
}
Exception Events
An alternative to trapping VISA errors by checking the return status after each VISA call is to use the VISA exception event. On sessions where an exception event handler is installed and VI_EVENT_EXCEPTION is enabled, the exception event handler is called whenever an error occurs while executing an operation.
Exception Handling Model
The exception-handling model follows the event-handling model for callbacks, and it uses the same operations as those used for general event handling. For example, an application calls viInstallHandler and viEnableEvent to enable exception events. The exception event is like any other event in VISA, except that the queueing and suspended handler mechanisms are not allowed.
When an error occurs for a session operation, the exception handler is executed synchronously. That is, the operation that caused the exception blocks until the exception handler completes its execution. The exception handler is executed in the context of the same thread that caused the exception event.
When invoked, the exception handler can check the error condition and instruct the exception operation to take a specific action. It can instruct the exception operation to continue normally (by returning VI_SUCCESS) or to not invoke any additional handlers in the case of handler nesting (by returning VI_SUCCESS_NCHAIN).
As noted, an exception operation blocks until the exception handler execution is completed. However, an exception handler sometimes may prefer to terminate the program prematurely without returning the control to the operation generating the exception. VISA does not preclude an application from using a platform-specific or language-specific exception handling mechanism from within the VISA exception handler.
For example, the C++ try/catch block can be used in an application in conjunction with the C++ throw mechanism from within the VISA exception handler. When using the C++ try/catch/throw or other exception-handling mechanisms, the control will not return to the VISA system. This has several important repercussions:
- If multiple handlers were installed on the exception event, the handlers that were not invoked prior to the current handler will not be invoked for the current exception.
- The exception context will not be deleted by the VISA system when a C++ exception is used. In this case, the application should delete the exception context as soon as the application has no more use for the context, before terminating the session. An application should use the viClose operation to delete the exception context.
- Code in any operation (after calling an exception handler) may not be called if the handler does not return. For example, local allocations must be freed before invoking the exception handler, rather than after it.
One situation in which an exception event will not be generated is in the case of asynchronous operations. If the error is detected after the operation is posted (i.e., once the asynchronous portion has begun), the status is returned normally via the I/O completion event.
However, if an error occurs before the asynchronous portion begins (i.e., the error is returned from the asynchronous operation itself), then the exception event will still be raised. This deviation is due to the fact that asynchronous operations already raise an event when they complete, and this I/O completion event may occur in the context of a separate thread previously unknown to the application. In summary, a single application event handler can easily handle error conditions arising from both exception events and failed asynchronous operations.
Using the VI_EVENT_EXCEPTION Event
You can use the VI_EVENT_EXCEPTION event as notification that an error condition has occurred during an operation invocation. The following table describes the VI_EVENT_EXCEPTION event attributes.
Attribute Name |
Attribute Value |
Access | Privilege |
Data Type |
Range |
Default |
---|---|---|---|---|---|---|
VI_ATTR_EVENT_TYPE |
0x3FFF4010UL |
RO |
Global |
ViEventType |
VI_EVENT_EXCEPTION |
N/A |
VI_ATTR_STATUS |
0x3FFF4025UL |
RO |
Global |
ViStatus |
N/A |
N/A |
VI_ATTR_OPER_NAME |
0xBFFF4042UL |
RO |
Global |
ViString |
N/A |
N/A |
Example: Exception Events
/* This is an example of how to use exception events to trap VISA errors. An exception event handler must be installed and exception events enabled on all sessions where the exception handler is used.*/
#include <stdio.h>
#include <visa.h>
ViStatus __stdcall myExceptionHandler (
ViSession vi,
ViEventType eventType,
ViEvent context,
ViAddr usrHandle
) {
ViStatus exceptionErrNbr; char nameBuffer[256];
ViString functionName = nameBuffer; char errStrBuffer[256];
/* Get the error value from the exception context */
viGetAttribute( context, VI_ATTR_STATUS, &exceptionErrNbr );
/* Get the function name from the exception context */
viGetAttribute( context, VI_ATTR_OPER_NAME, functionName );
errStrBuffer[0] = 0;
viStatusDesc( vi, exceptionErrNbr, errStrBuffer );
printf("ERROR: Exception Handler reports\n"
"(%s)\n","VISA function '%s' failed with
error 0x%lx\n", "functionName,
exceptionErrNbr, errStrBuffer );
return VI_SUCCESS;
}
void main(){
ViStatus status;
ViSession drm;
ViSession vi;
ViAddr myUserHandle = 0;
status = viOpenDefaultRM( &drm );
if ( status < VI_SUCCESS ) {
printf( "ERROR: viOpenDefaultRM failed with
error = 0x%lx\n", status );
return;
}
/* Install the exception handler and enable events for it */
status = viInstallHandler(drm,
VI_EVENT_EXCEPTION, myExceptionHandler,
myUserHandle);
if ( status < VI_SUCCESS )
{
printf( "ERROR: viInstallHandler failed
with error 0x%lx\n", status );
}
status = viEnableEvent(drm, VI_EVENT_EXCEPTION,
VI_HNDLR, VI_NULL);
if ( status < VI_SUCCESS ) {
printf( "ERROR: viEnableEvent failed with
error 0x%lx\n", status );
}
/* Generate an error to demonstrate that the
handler will be called */
status = viOpen( drm, "badVisaName", NULL,
NULL, &vi );
if ( status < VI_SUCCESS ) {
printf("ERROR: viOpen failed with error
0x%lx\n"
"Exception Handler should have been
called\n"
"before this message was printed.\n",status
);
}
}